/***********************************************************************************************************************
 * ############################################# Application AdewebLite #############################################
 * AdewebLite Android est une application permettant de consulter des emplois du temps fournis par l'université UHP
 * avec ou sans connexion internet (informations gardées en mémoire à chaque synchronisation). Et utilisant la web
 * API ADE pour collecter les données.
 * @author Andrianjafintrimo Victor, Zanette Sébastien
 * 
 * Basée sur l'application du même nom, utilisant le flux RSS (données à traiter), de :
 * @author Schnell Michaël, Zanette Sébastien
 * **********************************************************************************************************************
 */

package ade.schedule;

import ade.database.Database;
import java.util.ArrayList;
import java.util.Iterator;

/**
 * Comparaison de 2 emplois du temps et interclassement par ordre croissant d'id.
 * @author Zanette Sébastien, @author Andrianjafintrimo Victor
 */
public class GuidScheduleUpdater extends ScheduleUpdater {
	
	protected ArrayList<Lesson> oldLessons ;

        /**
         * Creer une instance de <code>GuidScheduleUpdater</code>.
         */
	public GuidScheduleUpdater() {
		super() ;
	}// GuidScheduleUpdater()

        /**
         * Comparaison de 2 emplois du temps, basé sur l'id des lessons.
         * @param oldS ancien emploi du temps (dans la base de données).
         * @param newS emploi du temps récupéré
         */
	@Override
	protected void compareS(Schedule oldS, Schedule newS) {
		this.insert.ensureCapacity(newS.getNLessons()) ;
		this.update.ensureCapacity(oldS.getNLessons()) ;
		this.delete.ensureCapacity(oldS.getNLessons()) ;
		this.buildOldIds(oldS) ;
		for(Lesson newLesson : newS) {
			long newId = newLesson.getLessonId() ;
			// lesson is old => guid known
			int indexOf = this.indexOf(newId) ;
			if (indexOf != -1) {
				// lesson is changed => update
				Lesson oldLesson = GuidScheduleUpdater.getLesson(oldS, newId) ;
				if (!oldLesson.equals(newLesson)) {
					this.update.add(newLesson) ;
					newLesson.setType(oldLesson.getType()) ;
                                        //change le statut de représentant le niveau de changement
                                        newLesson.setChange(oldLesson.getLevelChange(newLesson)) ;
                                        if (newLesson.getChange() == Lesson.BIG_CHANGE){
                                            Database db = new Database();
                                            db.insertLessonHistory(oldLesson);
                                        }
				}// if
				this.removeId(indexOf) ;
			} else {
				// lesson is new => guid unknown
				this.insert.add(newLesson) ;
			}// if
		}// for
		// The remaining ids in oldIds have to be removed
		for(Lesson lesson : this.oldLessons) {
			this.delete.add(lesson) ;
		}// for
		this.oldLessons = null ;
	}// compareS(Schedule, Schedule)
	
        /**
         * Construit une liste d'emploi du temps par ordre croissant d'id grâce au tri par insertion.
         * @param schedule emploi du temps
         */
	protected void buildOldIds(Schedule schedule) {
		this.oldLessons = new ArrayList<Lesson>(schedule.getNLessons()) ;
		if (schedule.getNLessons() == 0) {
			return ;
		}// if
		Iterator<Lesson> iterator = schedule.iterator() ;
		this.oldLessons.add(iterator.next()) ;
		while (iterator.hasNext()) {
			Lesson lesson = iterator.next() ;
			int insertPosition = this.oldLessons.size() ;
			long lessonId = lesson.getLessonId() ;
			while ((insertPosition > 0) 
					&& (this.oldLessons.get(insertPosition-1).getLessonId() > lessonId)) {
				insertPosition-- ;
			}// while
			this.oldLessons.add(insertPosition, lesson) ;
		}// while
	}// buildOldIds(Schedule)
	
        /**
         * Retourne l'indice de la liste du cours passé grâce à son id.
         * Le recherche est dichotomique.
         * @param id id du cours
         * @return
         */
        protected int indexOf (long id) {
		boolean found = false ;
		int left = 0, right = this.oldLessons.size()-1 ;
		int middle = 0 ;
		while ((left <= right) && !found) {
			middle = (left + right) / 2 ;
			long currentId = this.oldLessons.get(middle).getLessonId() ;
			if (currentId == id) {
				found = true ;
			} else if (currentId < id) {
				left = middle+1 ;
			} else/* currentID > id */{
				right = middle-1 ;
			}// if
		}// while
		
		if (found) {
			return middle ;
		}// if
		return -1 ;
	}// isOldId(long)
	
        /**
         * Supprime un element de la liste de cours (cours de la BD).
         * @param removedPosition 
         */
	protected void removeId(int removedPosition) {
		this.oldLessons.remove(removedPosition) ;
	}// removeId(long)
	
        /**
         * Retourne le cours identifié par l'id en paramètre.
         * @param schedule emploi du temps
         * @param lessonId id du cours
         * @return cours identifié par l'id, null si pas de resultat
         */
	protected static Lesson getLesson(Schedule schedule, long lessonId) {
		for(Lesson lesson : schedule) {
			if (lesson.getLessonId() == lessonId && lesson.getSchedule().equals(schedule.getName())) {
				return lesson ;
			}// if
		}// for
		return null ;
	}// getLesson(Schedule schedule, long)

}// class GuidScheduleUpdater